package com.easychat.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import com.easychat.constants.Constants;
import com.easychat.entity.config.AppConfig;
import com.easychat.entity.dto.MessageSendDTO;
import com.easychat.entity.dto.SysSettingDTO;
import com.easychat.entity.dto.TokenUserInfoDTO;
import com.easychat.entity.enums.*;
import com.easychat.entity.po.*;
import com.easychat.entity.query.*;
import com.easychat.entity.vo.UserInfoVO;
import com.easychat.exception.BusinessException;
import com.easychat.mappers.*;
import com.easychat.redis.RedisComponent;
import com.easychat.service.UserContactApplyService;
import com.easychat.websocket.ChannelContextUtils;
import com.easychat.websocket.MessageHandler;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import com.easychat.entity.vo.PaginationResultVO;
import com.easychat.service.GroupInfoService;
import com.easychat.utils.StringTools;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;


/**
 * 群组信息 业务接口实现
 */
@Service("groupInfoService")
public class GroupInfoServiceImpl implements GroupInfoService {

	@Resource
	private GroupInfoMapper<GroupInfo, GroupInfoQuery> groupInfoMapper;
	@Resource
	private UserInfoMapper<UserInfo, UserInfoQuery> userInfoMapper;
	@Resource
	private UserContactMapper<UserContact, UserContactQuery> userContactMapper;
	@Resource
	private ChatSessionMapper<ChatSession, ChatSessionQuery> chatSessionMapper;
	@Resource
	private ChatSessionUserMapper<ChatSessionUser, ChatSessionUserQuery> chatSessionUserMapper;
	@Resource
	private ChatMessageMapper<ChatMessage, ChatMessageQuery> chatMessageMapper;
	@Resource
	@Lazy     //避免循环依赖报错
	private GroupInfoService groupInfoService;
	@Resource
	private UserContactApplyService userContactApplyService;
	@Resource
	private RedisComponent redisComponent;
	@Resource
	private AppConfig appConfig;
	@Resource
	private MessageHandler messageHandler;
	@Resource
	private ChannelContextUtils channelContextUtils;


	/**
	 * 根据条件查询列表
	 */
	@Override
	public List<GroupInfo> findListByParam(GroupInfoQuery param) {
		return this.groupInfoMapper.selectList(param);
	}

	/**
	 * 根据条件查询列表
	 */
	@Override
	public Integer findCountByParam(GroupInfoQuery param) {
		return this.groupInfoMapper.selectCount(param);
	}

	/**
	 * 分页查询方法
	 */
	@Override
	public PaginationResultVO<GroupInfo> findListByPage(GroupInfoQuery param) {
		int count = this.findCountByParam(param);
		int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

		SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
		param.setSimplePage(page);
		List<GroupInfo> list = this.findListByParam(param);
		PaginationResultVO<GroupInfo> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
		return result;
	}

	/**
	 * 新增
	 */
	@Override
	public Integer add(GroupInfo bean) {
		return this.groupInfoMapper.insert(bean);
	}

	/**
	 * 批量新增
	 */
	@Override
	public Integer addBatch(List<GroupInfo> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.groupInfoMapper.insertBatch(listBean);
	}

	/**
	 * 批量新增或者修改
	 */
	@Override
	public Integer addOrUpdateBatch(List<GroupInfo> listBean) {
		if (listBean == null || listBean.isEmpty()) {
			return 0;
		}
		return this.groupInfoMapper.insertOrUpdateBatch(listBean);
	}

	/**
	 * 多条件更新
	 */
	@Override
	public Integer updateByParam(GroupInfo bean, GroupInfoQuery param) {
		StringTools.checkParam(param);
		return this.groupInfoMapper.updateByParam(bean, param);
	}

	/**
	 * 多条件删除
	 */
	@Override
	public Integer deleteByParam(GroupInfoQuery param) {
		StringTools.checkParam(param);
		return this.groupInfoMapper.deleteByParam(param);
	}

	/**
	 * 根据GroupId获取对象
	 */
	@Override
	public GroupInfo getGroupInfoByGroupId(String groupId) {
		return this.groupInfoMapper.selectByGroupId(groupId);
	}

	/**
	 * 根据GroupId修改
	 */
	@Override
	public Integer updateGroupInfoByGroupId(GroupInfo bean, String groupId) {
		return this.groupInfoMapper.updateByGroupId(bean, groupId);
	}

	/**
	 * 根据GroupId删除
	 */
	@Override
	public Integer deleteGroupInfoByGroupId(String groupId) {
		return this.groupInfoMapper.deleteByGroupId(groupId);
	}

	/**
	 * 创建群组
	 * @param groupInfo 群组信息对象
	 * @param avatarFile 头像文件
	 * @param avatarCover 头像封面，缩略图
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveGroup(GroupInfo groupInfo, MultipartFile avatarFile, MultipartFile avatarCover) throws IOException {
		Date date = new Date();
		if (StringTools.isEmpty(groupInfo.getGroupId())) {//新增操作 需要上传头像文件
			//查询目前此用户创建群的总数（不能超过系统设置中的最大数量）
			GroupInfoQuery groupInfoQuery = new GroupInfoQuery();
			groupInfoQuery.setGroupOwnerId(groupInfo.getGroupOwnerId());
			Integer groupCreatedNumber = groupInfoMapper.selectCount(groupInfoQuery);
			SysSettingDTO sysSetting = redisComponent.getSysSetting();//获取系统设置
			if (groupCreatedNumber >= sysSetting.getMaxGroupCount()) {
				//此用户创建的群总数超过了系统设置的最大数量
				throw new BusinessException("最多只能创建" + sysSetting.getMaxGroupCount() + "个群聊");
			}
			//新增操作 需要上传头像文件
			if (avatarFile == null) {
				throw new BusinessException(ResponseCodeEnum.CODE_600);
			}
			//生成groupId groupId共12位，"G" + 11位随机序列 ”G“开头代表群ID
			groupInfo.setGroupId(StringTools.getGroupId());
			//设置创建时间
			groupInfo.setCreateTime(date);
			//保存数据
			groupInfoMapper.insert(groupInfo);

			//将群组保存为联系人(user_contact表)
			UserContact userContact = new UserContact();
			userContact.setUserId(groupInfo.getGroupOwnerId());
			userContact.setContactId(groupInfo.getGroupId());
			userContact.setContactType(UserTypeEnum.GROUP.getType());
			userContact.setStatus(UserContactStatusEnum.FRIEND.getStatus());
			userContact.setCreateTime(date);
			userContact.setLastUpdateTime(date);
			userContactMapper.insert(userContact);

			//创建会话
			String sessionId = StringTools.getChatSessionId4Group(groupInfo.getGroupId());
			ChatSession chatSession = new ChatSession();
			chatSession.setSessionId(sessionId);
			chatSession.setLastMessage(MessageTypeEnum.GROUP_CREATE.getInitMessage());
			chatSession.setLastReceiveTime(date.getTime());
			chatSessionMapper.insertOrUpdate(chatSession);

			//会话人信息
			ChatSessionUser chatSessionUser = new ChatSessionUser();
			chatSessionUser.setUserId(groupInfo.getGroupOwnerId());
			chatSessionUser.setContactId(groupInfo.getGroupId());
			chatSessionUser.setContactName(groupInfo.getGroupName());
			chatSessionUser.setSessionId(sessionId);
			chatSessionUserMapper.insert(chatSessionUser);

			//创建消息
			ChatMessage chatMessage = new ChatMessage();
			chatMessage.setSessionId(sessionId);
			chatMessage.setMessageType(MessageTypeEnum.GROUP_CREATE.getType());
			chatMessage.setMessageContent(MessageTypeEnum.GROUP_CREATE.getInitMessage());
			chatMessage.setSendTime(date.getTime());
			chatMessage.setContactId(groupInfo.getGroupId());
			chatMessage.setContactType(UserTypeEnum.GROUP.getType());
			chatMessage.setStatus(MessageStatusEnum.COMPLETED.getStatus());
			chatMessageMapper.insert(chatMessage);

			//向redis缓存中添加联系人信息
			redisComponent.saveUserContact(groupInfo.getGroupOwnerId(), groupInfo.getGroupId());

			//将群主id对应的channel添加到groupId对应的channelGroup
			channelContextUtils.addUser2Group(groupInfo.getGroupOwnerId(), groupInfo.getGroupId());

			//发送消息
			chatSessionUser.setLastMessage(MessageTypeEnum.GROUP_CREATE.getInitMessage());
			chatSessionUser.setLastReceiveTime(date.getTime());
			chatSessionUser.setMemberCount(1);//群人数，群刚刚创建，群员只有群主

			MessageSendDTO messageSendDTO = new MessageSendDTO();
			BeanUtils.copyProperties(chatMessage, messageSendDTO);
			messageSendDTO.setExtendData(chatSessionUser);
			messageSendDTO.setLastMessage(chatSessionUser.getLastMessage());

			messageHandler.sendMessage(messageSendDTO);
		} else {//修改操作
			//根据groupId查询数据库中的数据
			GroupInfo dbGroupInfo = groupInfoMapper.selectByGroupId(groupInfo.getGroupId());
			//不是群主，却要进行修改操作（传过来的ownerId不等于数据库中存的ownerId）
			if (!dbGroupInfo.getGroupOwnerId().equals(groupInfo.getGroupOwnerId())) {
				throw new BusinessException(ResponseCodeEnum.CODE_600);
				//如果不加这个判断，就能直接通过接口，传入其他人建的群的groupId，修改其信息
			}
			groupInfoMapper.updateByGroupId(groupInfo, groupInfo.getGroupId());
			//更新相关表冗余信息 chat_session_user表中的contact_name字段
			String contactNameUpdate = null;//更新后的群名称
			if (!dbGroupInfo.getGroupName().equals(groupInfo.getGroupName())) {
				contactNameUpdate = groupInfo.getGroupName();//需要更新群名称
			}
			if (contactNameUpdate != null) {
				//需要更新群名称
				//更新相关表冗余信息
				ChatSessionUser updateInfo = new ChatSessionUser();
				updateInfo.setContactName(contactNameUpdate);
				ChatSessionUserQuery chatSessionUserQuery = new ChatSessionUserQuery();
				chatSessionUserQuery.setContactId(groupInfo.getGroupId());
				chatSessionUserMapper.updateByParam(updateInfo, chatSessionUserQuery);//更新对应contactId(groupId)的contactName
				//修改群昵称，发送ws消息(不入库)
				MessageSendDTO messageSendDTO = new MessageSendDTO();
				messageSendDTO.setContactType(UserTypeEnum.GROUP.getType());
				messageSendDTO.setContactId(groupInfo.getGroupId());
				messageSendDTO.setExtendData(contactNameUpdate);
				messageSendDTO.setMessageType(MessageTypeEnum.CONTACT_NAME_UPDATE.getType());
				messageHandler.sendMessage(messageSendDTO);
			}
		}
		if (avatarFile == null) {
			return;
		}
		//文件根目录
		String baseFolder = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE;//文件存储路径
		//头像存储目录
		File avatarFileFolder = new File(baseFolder + Constants.FILE_FOLDER_AVATAR);
		if (!avatarFileFolder.exists()){
			avatarFileFolder.mkdirs();
		}
		//图片文件命名规则：groupId.png
		//保存原图和缩略图
		String filePath = avatarFileFolder.getPath() + "/" + groupInfo.getGroupId() + Constants.IMAGE_EXTENSION;
//		String coverPath = avatarFileFolder.getPath() + "/" + groupInfo.getGroupId() + Constants.COVER_IMAGE_EXTENSION;
		avatarFile.transferTo(new File(filePath));
		avatarCover.transferTo(new File(filePath + Constants.COVER_IMAGE_EXTENSION));
	}

	/**
	 * 解散群组
	 * @param groupOwnerId
	 * @param groupId
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void dissolutionGroup(String groupOwnerId, String groupId) {
		GroupInfo dbInfo = groupInfoMapper.selectByGroupId(groupId);
		if (dbInfo == null || !dbInfo.getGroupOwnerId().equals(groupOwnerId)) {
			//绕过了前端，传入的groupOwnerId不是groupId群组的真实群主
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		//解散群组，只需要修改状态
		GroupInfo updateInfo = new GroupInfo();
		updateInfo.setStatus(GroupStatusEnum.DISBAND.getStatus());
		groupInfoMapper.updateByGroupId(updateInfo, groupId);
		//更新联系人信息
		//where
		UserContactQuery userContactQuery = new UserContactQuery();
		userContactQuery.setContactType(UserTypeEnum.GROUP.getType());
		userContactQuery.setContactId(groupId);
		//set
		UserContact userContact = new UserContact();
		userContact.setStatus(UserContactStatusEnum.DELETE.getStatus());
		userContact.setLastUpdateTime(new Date());
		//更新
		userContactMapper.updateByParam(userContact, userContactQuery);
		//TODO 移除相关群员的联系人缓存
		//该群对应的所有联系人信息
		List<UserContact> userContactList = userContactMapper.selectList(userContactQuery);
		for (UserContact userContact1 : userContactList) {
			redisComponent.removeUserContact(userContact1.getUserId(), userContact1.getContactId());
		}

		//更新会话
		//获取群id对应的会话id
		String sessionId = StringTools.getChatSessionId4Group(groupId);
		Date curDate = new Date();
		//群解散消息
		String messageContent = MessageTypeEnum.DISSOLUTION_GROUP.getInitMessage();
		ChatSession chatSession = new ChatSession();
		chatSession.setLastMessage(messageContent);
		chatSession.setLastReceiveTime(curDate.getTime());
		//更新
		chatSessionMapper.updateBySessionId(chatSession, sessionId);

		//插入消息
		ChatMessage chatMessage = new ChatMessage();
		chatMessage.setSessionId(sessionId);
		chatMessage.setSendTime(curDate.getTime());
		chatMessage.setContactType(UserTypeEnum.GROUP.getType());
		chatMessage.setStatus(MessageStatusEnum.COMPLETED.getStatus());
		chatMessage.setMessageType(MessageTypeEnum.DISSOLUTION_GROUP.getType());
		chatMessage.setContactId(groupId);
		chatMessage.setMessageContent(messageContent);
		chatMessageMapper.insert(chatMessage);

		//发送消息
		MessageSendDTO messageSendDTO = new MessageSendDTO();
		BeanUtils.copyProperties(chatMessage, messageSendDTO);
		messageHandler.sendMessage(messageSendDTO);
		//TODO 发信息：更新会话信息，记录群消息，发送解散通知消息
	}

	/**
	 * 添加用户到群聊/移除群聊中的用户
	 * @param tokenUserInfoDTO 操作者token(必须为群主)
	 * @param groupId 群id
	 * @param selectContacts 选择的联系人id 逗号分割
	 * @param opType 操作类型 0移除 1添加
	 * @return
	 */
	@Override
	public void addOrRemoveGroupUser(TokenUserInfoDTO tokenUserInfoDTO, String groupId, String selectContacts, Integer opType) {
		GroupInfo groupInfo = groupInfoMapper.selectByGroupId(groupId);
		if (groupInfo == null || !groupInfo.getGroupOwnerId().equals(tokenUserInfoDTO.getUserId())) {
			//群不存在/操作这不是群主
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		Date curDate = new Date();
		String[] selectIdList = selectContacts.split(",");
		for (String selectId : selectIdList) {
			if (opType.equals(OpTypeEnum.REMOVE.getType())) {
				//移除成员
				//不能直接调用leaveGroup，这样事务不生效
				groupInfoService.leaveGroup(selectId, groupId, MessageTypeEnum.REMOVE_GROUP);
			} else {
				//添加成员
				UserContactApply userContactApply = new UserContactApply();
				userContactApply.setApplyUserId(selectId);
				userContactApply.setReceiveUserId(tokenUserInfoDTO.getUserId());
				userContactApply.setContactId(groupId);
				userContactApply.setContactType(UserTypeEnum.GROUP.getType());
				userContactApply.setApplyInfo(null);
				userContactApplyService.addContact(userContactApply);
			}
		}

	}

	/**
	 * 离开群聊
	 * @param userId 离开群聊的用户
	 * @param groupId 群id
	 * @param messageTypeEnum 消息类型  LEAVE_GROUP %s退出了群聊 REMOVE_GROUP %s被管理员移除了群聊
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void leaveGroup(String userId, String groupId, MessageTypeEnum messageTypeEnum) {
		GroupInfo groupInfo = groupInfoMapper.selectByGroupId(groupId);
		if (groupInfo == null) {
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		if (userId.equals(groupInfo.getGroupOwnerId())) {
			// 群主自己不能离开群聊
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}
		//移除联系人信息
		Integer count = userContactMapper.deleteByUserIdAndContactId(userId, groupId);
		if (count == 0) {
			// 如果删除了0条数据，说明参数错误
			throw new BusinessException(ResponseCodeEnum.CODE_600);
		}

		//更新会话
		UserInfo userInfo = userInfoMapper.selectByUserId(userId);
		String messageContent = String.format(messageTypeEnum.getInitMessage(), userInfo.getNickName());//%s退出了群聊 或者 %s被管理员移出群聊
		String sessionId = StringTools.getChatSessionId4Group(groupId);
		Date curDate = new Date();

		ChatSession chatSession = new ChatSession();
		chatSession.setSessionId(sessionId);
		chatSession.setLastMessage(messageContent);
		chatSession.setLastReceiveTime(curDate.getTime());
		chatSessionMapper.updateBySessionId(chatSession, sessionId);

		//新增消息
		ChatMessage chatMessage = new ChatMessage();
		chatMessage.setSessionId(sessionId);
		chatMessage.setMessageContent(messageContent);
		chatMessage.setContactId(groupId); //发给群里所有人
		chatMessage.setContactType(UserTypeEnum.GROUP.getType());
		chatMessage.setMessageType(messageTypeEnum.getType());
		chatMessage.setSendTime(curDate.getTime());
		chatMessage.setStatus(MessageStatusEnum.COMPLETED.getStatus());
		chatMessageMapper.insert(chatMessage);

		//发送ws消息
		MessageSendDTO messageSendDTO = new MessageSendDTO();
		BeanUtils.copyProperties(chatMessage, messageSendDTO);
		//更新群人数
		UserContactQuery userContactQuery = new UserContactQuery();
		userContactQuery.setContactId(groupId);
		userContactQuery.setStatus(UserContactStatusEnum.FRIEND.getStatus());
		Integer memberCount = userContactMapper.selectCount(userContactQuery);
		messageSendDTO.setMemberCount(memberCount);
		messageSendDTO.setExtendData(userId);
		messageHandler.sendMessage(messageSendDTO);
	}
}